package vn.fpt.snake.unitTest;

import static org.junit.Assert.*;

import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import junit.framework.Assert;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import vn.fpt.snake.commons.Direction;
import vn.fpt.snake.controller.SnakeControllerImpl;
import vn.fpt.snake.dataAccess.DataAccess;
import vn.fpt.snake.entity.AbstractFruit;
import vn.fpt.snake.entity.Apple;
import vn.fpt.snake.entity.Chili;
import vn.fpt.snake.entity.Settings;
import vn.fpt.snake.entity.Snake;
import vn.fpt.snake.entity.Watermelon;
import vn.fpt.snake.ui.OverGameViewImpl;
import vn.fpt.snake.view.Board;

public class SnakeControllerImplTest {
	DataAccess da;
	Settings settings;
	SnakeControllerImpl snakeController;
	Board board;
	@BeforeClass
	public static void setUpBeforeClass() throws Exception {
	}

	@AfterClass
	public static void tearDownAfterClass() throws Exception {
	}

	@Before
	public void setUp() throws Exception {	
		da = new DataAccess();
		settings = da.getSettings();
		board = new Board(new JFrame());
		snakeController = new SnakeControllerImpl(board);
	}

	@After
	public void tearDown() throws Exception {
	}

	@Test
	public void testCreateNewSnake() throws Exception{
		int dots = settings.getDots();
		int score = 0;
		//Image dot = Resource.dotImage;
		//Image head = Resource.headImage;

		Snake snake = snakeController.createNewSnake();
		Assert.assertTrue(snake != null);
		Assert.assertEquals(dots, snake.getDots());
		Assert.assertEquals(score, snake.getScore());
		///Assert.assertEquals(dot, snake.getDot());
		//Assert.assertEquals(head, snake.getHead());
	}

	@Test
	public void testMove_InputSnakeAndDirect_ExpectSnake() {
		//For left direction
		int dotSize = settings.getDotSize();
		int width = settings.getWidth();
		Direction directInput = Direction.left;
		Snake snakeInput = new Snake(100);
		snakeInput.setDots(2);
		snakeInput.setX(0, dotSize * 1);
		snakeInput.setY(0, dotSize);
		snakeInput.setX(1, dotSize * 2);
		snakeInput.setY(1, dotSize);
		
		Snake expectedSnake = new Snake(100);
		expectedSnake.setDots(2);
		expectedSnake.setX(0, 0);
		expectedSnake.setY(0, dotSize);
		expectedSnake.setX(1, dotSize * 1);
		expectedSnake.setY(1, dotSize);
		
		Snake actualSnake = snakeController.move(snakeInput, directInput);
		
		//Test if snake not reach boundaries yet
		Assert.assertEquals(snakeInput.getX(0), actualSnake.getX(0));
		Assert.assertEquals(snakeInput.getX(1), actualSnake.getX(1));
		
		snakeInput = new Snake(100);
		snakeInput.setDots(2);
		snakeInput.setX(0, 0);
		snakeInput.setY(0, dotSize);
		snakeInput.setX(1, dotSize * 1);
		snakeInput.setY(1, dotSize);
		
		expectedSnake = new Snake(100);
		expectedSnake.setDots(2);
		expectedSnake.setX(0, width);
		expectedSnake.setY(0, dotSize);
		expectedSnake.setX(1, 0);
		expectedSnake.setY(1, dotSize);
		
		actualSnake = snakeController.move(snakeInput, directInput);
		
		//Test if snake reach boundaries
		Assert.assertEquals(snakeInput.getX(0), actualSnake.getX(0));
		Assert.assertEquals(snakeInput.getX(1), actualSnake.getX(1));
	}
	
	

	@Test
	public void testCheckCollision_InputBitedSnake_OverGameViewImpl() {
		try{
					
			Snake snakeInput = new Snake(100);
			snakeInput.setDots(2);
			snakeInput.setX(0, 10);
			snakeInput.setY(0, 10);
			snakeInput.setX(1, 10);
			snakeInput.setY(1, 10);
			
			snakeController.checkCollision(snakeInput);
			
			Assert.assertTrue(board._view instanceof OverGameViewImpl);		
		}catch(Exception e){
			fail("Error executing");
		}		
	}

	@Test
	public void testEatFruit_InputFruit_StatusOfGame() throws Exception{
		List<AbstractFruit> fruits = new ArrayList<AbstractFruit>();
		Apple apple = new Apple();
		apple.setX(102);
		apple.setY(82);
		Watermelon watermelon = new Watermelon();
		watermelon.setX(104);
		watermelon.setY(284);
		//watermelon.setIcon(Resource.watermelonImage);
		Chili chili = new Chili();
		chili.setX(167);
		chili.setY(147);
		fruits.add(apple);
		fruits.add(watermelon);
		fruits.add(chili);
		
		//Test apple
		Snake snakeInput = new Snake(100);
		snakeInput.setScore(10);
		snakeInput.setDots(2);
		snakeInput.setX(0, 102);
		snakeInput.setY(0, 82);
		snakeInput.setX(1, 43);
		snakeInput.setY(1, 124);
		
		boolean expectedValue = true;
		boolean actualValue = snakeController.eatFruit(snakeInput, fruits);
		
		Assert.assertEquals(expectedValue, actualValue);
		Assert.assertEquals(snakeInput.getScore() , 11);
		
		//Test watermelon
		snakeInput = new Snake(100);
		snakeInput.setScore(10);
		snakeInput.setDots(2);
		snakeInput.setX(0, 104);
		snakeInput.setY(0, 284);
		snakeInput.setX(1, 43);
		snakeInput.setY(1, 124);
		
		snakeController.eatFruit(snakeInput, fruits);
		
		Watermelon watermelonResult = null;
		for(AbstractFruit fruit : fruits){
			if(fruit instanceof Watermelon){
				watermelonResult = (Watermelon)fruit;
				break;
			}
		}
		
		Assert.assertFalse(watermelonResult == null);
		Assert.assertEquals(snakeInput.getScore(), 30);
		Assert.assertEquals(watermelonResult.getX(), -1);
		Assert.assertEquals(watermelonResult.getY(), -1);
		Assert.assertEquals(watermelonResult.getIcon(), null);
			
		//Test chili
		snakeInput = new Snake(100);
		snakeInput.setScore(10);
		snakeInput.setDots(2);
		snakeInput.setX(0, 167);
		snakeInput.setY(0, 147);
		snakeInput.setX(1, 43);
		snakeInput.setY(1, 124);
		
		snakeController.eatFruit(snakeInput, fruits);
		
		Chili chiliResult = null;
		for(AbstractFruit fruit : fruits){
			if(fruit instanceof Chili){
				chiliResult = (Chili)fruit;
				break;
			}
		}
		
		Assert.assertFalse(chiliResult == null);
		Assert.assertTrue(board._view instanceof OverGameViewImpl);		
	}

}
